<!-- 可不使用本组件，直接使用uview的组件-->
<template>
	<u-popup :show="showPopup" mode="bottom" border-radius="24" @close="close">
		<view class="calendar-container">
			<view class="calendar-header">
				<text class="title fw">{{ title }}</text>
				<view class="close" @click="close">
					<img :src="imgBaseUrl + 'close_icon.png'" />
				</view>
			</view>
			<view class="calendar-title">
				<view class="quick-wrap" v-if="mode == 'range' && showQuickModule">
					<view
						:class="['quick-item', { active: quickSelectIndex == index }]"
						v-for="(item, index) in quickList"
						:key="index"
						@click="quickSelect(index)"
					>
						{{ item }}
						<img
							v-if="quickSelectIndex == index"
							class="quick-item-img"
							:src="imgBaseUrl + 'quick-select.png'"
						/>
					</view>
				</view>
				<view class="weeks">
					<view class="week-name" v-for="(week, index) in weeks" :key="index">
						{{ week }}
					</view>
				</view>
				<view class="select-month">
					{{ filterMonth(currentMonth) }}
				</view>
			</view>
			<scroll-view
				:class="[
					'calendar-wrap',
					{ 'safe-area-inset-bottom': mode !== 'range' },
					{ 'range-calendar-wrap': mode === 'range' },
				]"
				:scroll-y="true"
				:scroll-into-view="scrollIntoViewItem"
				:scroll-top="scrollTop"
				@scroll="onScroll"
			>
				<view class="calendar-month" v-for="(monthItem, mIndex) in calendars" :key="mIndex">
					<view class="calendar-month-name" v-if="mIndex > 0">{{ filterMonth(monthItem.month) }}</view>
					<view class="day" :id="'month-' + mIndex">
						<view class="month-index">{{ filterMonthNum(monthItem.month) }}</view>
						<view
							class="day-item"
							v-for="(dayItem, dIndex) in monthItem.days"
							:key="dIndex"
							@click="selectDate(dayItem)"
						>
							<view
								:class="[
									'day-name',
									{ active: isCurrentDate(dayItem) && mode !== 'range' },
									{ disabled: disabledDate(dayItem) },
									{ isStartDate: isStartDate(dayItem) },
									{ isEndDate: isEndDate(dayItem) },
									{ isRangeDate: isRangeDate(dayItem) },
									{ isToday: isToday(dayItem) },
								]"
							>
								{{ filterDateNum(dayItem) }}
							</view>
						</view>
					</view>
				</view>
			</scroll-view>
			<view class="quick-operate" v-if="mode == 'range'">
				<view class="quick-reset" @click="resetRangeDate()">
					<img class="quick-item-img" :src="imgBaseUrl + 'clear-select.png'" />
					重置
				</view>
				<view class="quick-confirm">
					<view class="submit-button" @click="selectRangeDate">确认</view>
				</view>
			</view>
		</view>
	</u-popup>
</template>

<script setup lang="ts">
import { ref, inject } from "vue"
import dayjs from "dayjs"
import { isArray } from "lodash"
const instance = getCurrentInstance()?.proxy
const props = defineProps({
	show: {
		type: Boolean,
		default: false,
	},
	title: {
		type: String,
		default: "日期选择",
	},
	defaultDate: {
		type: String,
		default: "",
	},
	minDate: {
		type: String,
		default: dayjs().subtract(20, "M").format("YYYY-MM-DD"),
	},
	maxDate: {
		type: String,
		default: dayjs().add(6, "M").format("YYYY-MM-DD"),
	},
	defaultStartDate: {
		type: String,
		default: "",
	},
	defaultEndDate: {
		type: String,
		default: "",
	},
	mode: {
		type: String,
		default: "date",
	},
	maxRange: {
		type: Number,
		default: 367,
	},
	showQuickModule: {
		type: Boolean,
		default: true,
	},
})

const imgBaseUrl = inject("imgBaseUrl")

const filterDateNum = (val: string) => {
	return val ? dayjs(val).date() : ""
}
const filterMonthNum = (val: string) => {
	return val ? dayjs(val).month() + 1 : ""
}
const filterMonth = (val: string) => {
	return dayjs(val || dayjs()).format("YYYY年MM月")
}

watch(
	() => props.show,
	(newVal) => {
		showPopup.value = newVal
		newVal && initCalendar()
	},
)
watch(
	() => props.minDate,
	(newVal) => {
		newVal && initCalendar()
	},
)
watch(
	() => props.maxDate,
	(newVal) => {
		newVal && initCalendar()
	},
)
watch(
	() => props.defaultDate,
	(newVal) => {
		if (newVal) {
			currentDate.value = dayjs(newVal).format("YYYY-MM-DD")
			scrollIntoView()
		}
	},
)
watch(
	() => props.defaultStartDate,
	(newVal) => {
		if (newVal) {
			startDate.value = dayjs(newVal).format("YYYY-MM-DD")
		}
	},
)
watch(
	() => props.defaultEndDate,
	(newVal) => {
		if (newVal) {
			endDate.value = dayjs(newVal).format("YYYY-MM-DD")
		}
	},
)

const quickList = ["本月", "本季度", "本年"]
const weeks = ["日", "一", "二", "三", "四", "五", "六"]

const { title, minDate, maxDate, mode, maxRange, showQuickModule } = toRefs(props)
const quickSelectIndex = ref<number>(-1)
const monthNameHeight = ref<number>(0)
const endDate = ref<string>("")
const startDate = ref<string>("")
const monthDomHeights = ref<number[]>([])
const scrollTop = ref<number>(0)
const scrollIntoViewItem = ref<string>("")
const currentDate = ref<string>(dayjs().format("YYYY-MM-DD"))
const currentMonth = ref<string>(dayjs().format("YYYY-MM"))
const calendars = ref<any[]>([])
const showPopup = ref<boolean>(false)

const emit = defineEmits(["close", "confirm"])

const onScroll = (e: any) => {
	const scrollTop = e.detail.scrollTop
	let height = 0
	for (let i = 0; i < monthDomHeights.value.length; i++) {
		height += monthDomHeights.value[i]
		if (scrollTop < height + monthNameHeight.value / 2) {
			currentMonth.value = calendars.value[i].month
			break
		}
	}
}
const scrollIntoView = () => {
	if (!currentDate.value) {
		return
	}
	let monthIndex = calendars.value.findIndex((month) => compareMonth(month.month, currentDate.value))
	scrollIntoViewItem.value = `month-${monthIndex}`
	scrollTop.value = 0
	monthDomHeights.value.map((height, index) => {
		if (index < monthIndex) {
			scrollTop.value += height
		}
	})
	uni.createSelectorQuery()
		.in(instance)
		.select(".calendar-month-name")
		.boundingClientRect((rect) => {
			if (!isArray(rect)) {
				scrollTop.value = scrollTop.value + (rect?.height || 0) * 2 + Math.random()
			}
		})
		.exec()
}
const initCalendar = () => {
	const minRangeDate = dayjs(minDate.value).format("YYYY-MM-01"),
		maxRangeDate = `${dayjs(maxDate.value).format("YYYY-MM")}-${dayjs(maxDate.value).daysInMonth()}`
	let months = new Map(),
		curDate = minRangeDate,
		curMonth = dayjs(curDate).format("YYYY-MM")
	while (!dayjs(curDate).isAfter(maxRangeDate)) {
		if (compareMonth(curDate, curMonth)) {
			if (months.get(curMonth)?.length) {
				months.get(curMonth).push(curDate)
			} else {
				months.set(curMonth, [curDate])
			}
		} else {
			curMonth = dayjs(curDate).format("YYYY-MM")
			months.set(curMonth, [curDate])
		}
		curDate = dayjs(curDate).add(1, "d").format("YYYY-MM-DD")
	}
	calendars.value = []
	months.forEach((values, key) => {
		let firstDayOfMonth = dayjs(values[0]).day()
		calendars.value.push({
			month: key,
			days: [...new Array(firstDayOfMonth).fill(""), ...values],
		})
	})
	setTimeout(() => {
		initMonthDomRect()
	})
}
const initMonthDomRect = () => {
	uni.createSelectorQuery()
		.in(instance)
		.selectAll(".calendar-month")
		.boundingClientRect((monthRectArr) => {
			monthDomHeights.value = []
			if (isArray(monthRectArr)) {
				monthRectArr.map((rect) => monthDomHeights.value.push(rect?.height || 0))
				scrollIntoView()
			}
		})
		.selectAll(".calendar-month-name")
		.boundingClientRect((monthRectArr) => {
			monthNameHeight.value = monthRectArr[0]?.height
		})
		.exec()
}
const quickSelect = (e: number) => {
	quickSelectIndex.value = e
	if (e === 0) {
		startDate.value = dayjs().startOf("month").format("YYYY-MM-DD")
		endDate.value = dayjs().endOf("month").format("YYYY-MM-DD")
	} else if (e === 1) {
		const now = dayjs()
		const month = now.month() + 1 // dayjs中月份是从0开始的
		const quarter = Math.ceil(month / 3)
		startDate.value = dayjs()
			.month((quarter - 1) * 3)
			.startOf("month")
			.format("YYYY-MM-DD")
		endDate.value = dayjs()
			.month((quarter - 1) * 3 + 2)
			.endOf("month")
			.format("YYYY-MM-DD")
	} else {
		startDate.value = dayjs().startOf("year").format("YYYY-MM-DD")
		endDate.value = dayjs().endOf("year").format("YYYY-MM-DD")
	}
}
const resetRangeDate = () => {
	startDate.value = ""
	endDate.value = ""
	quickSelectIndex.value = -1
}
const selectRangeDate = () => {
	if (startDate.value) {
		emit("confirm", [startDate.value, endDate.value || startDate.value])
	} else {
		emit("confirm", [])
	}
}
const compareMonth = (val1: string, val2: string) => {
	return dayjs(val1).format("YYYY-MM") == dayjs(val2).format("YYYY-MM")
}
const isCurrentDate = (date: string) => {
	return date == currentDate.value
}
const isStartDate = (date: string) => {
	return startDate.value && date == startDate.value
}
const isEndDate = (date: string) => {
	return endDate.value && date == endDate.value
}
const isRangeDate = (date: string) => {
	if (startDate.value && endDate.value) {
		return dayjs(date).isBefore(endDate.value) && dayjs(date).isAfter(startDate.value)
	} else {
		return false
	}
}
const isToday = (date: string) => {
	return date == dayjs().format("YYYY-MM-DD")
}
const disabledDate = (date: string) => {
	return dayjs(date).isBefore(minDate.value) || dayjs(date).isAfter(maxDate.value)
}
const selectDate = (date: string) => {
	if (disabledDate(date)) {
		return
	}
	// 选择时间范围
	if (mode.value === "range") {
		quickSelectIndex.value = -1
		// 如果有开始时间与结束时间 则重新选择开始结束时间
		if (startDate.value && endDate.value) {
			startDate.value = ""
			startDate.value = date
			endDate.value = ""
		} else {
			// 如果选了开始时间
			if (startDate.value) {
				if (date == startDate.value) return
				// 在开始时间之前则重新定位开始时间
				if (dayjs(date).isBefore(dayjs(startDate.value))) {
					endDate.value = ""
					startDate.value = date
				} else {
					// 先判断是否超过可选最大值
					if (dayjs(date).diff(dayjs(startDate.value), "day") >= maxRange.value) {
						return uni.showToast({
							title: `暂不支持超过1年的查询`,
							icon: "none",
						})
					}
					// 不然则为结束时间
					endDate.value = date
				}
			} else {
				// 没选开始时间为开始时间
				startDate.value = date
				endDate.value = ""
			}
		}
	} else {
		// 选择单个日期
		currentDate.value = date
		emit("confirm", currentDate)
	}
}
const close = () => {
	emit("close")
}
</script>

<style lang="scss" scoped>
.calendar-container {
	view {
		box-sizing: border-box;
	}
	.calendar-header {
		height: 116rpx;
		text-align: center;
		position: sticky;
		top: 0;
		border-bottom: 2rpx solid #eeeeee;
		background: #fff;
		padding-top: 40rpx;
		.title {
			font-size: 32rpx;
			color: #333;
		}
		.close {
			position: absolute;
			top: 26rpx;
			right: 20rpx;
			padding: 20rpx;
			image {
				width: 32rpx;
				height: 32rpx;
			}
		}
	}
	.calendar-title {
		.quick-wrap {
			display: flex;
			padding: 20rpx 28rpx;
			justify-content: space-between;
			.quick-item {
				width: 212rpx;
				height: 64rpx;
				background: #f4f6f9;
				border-radius: 8rpx;
				font-size: 24rpx;
				color: #333333;
				display: flex;
				align-items: center;
				justify-content: center;
				position: relative;
				border-radius: 12rpx;
				.quick-item-img {
					width: 24rpx;
					height: 24rpx;
					position: absolute;
					bottom: -2rpx;
					right: -2rpx;
				}
			}
			& > .active {
				border: 1px solid #0aaeff;
				color: #0aaeff;
				background: rgba(10, 174, 255, 0.12);
				font-weight: bold;
			}
		}
		.select-month {
			font-size: 28rpx;
			height: 88rpx;
			line-height: 88rpx;
			text-align: center;
			color: #333;
			font-weight: bold;
		}
		.weeks {
			height: 60rpx;
			display: flex;
			align-items: center;
			box-shadow: 0rpx 14rpx 20rpx 0rpx rgba(125, 126, 128, 0.16);
			.week-name {
				flex: 1;
				font-size: 24rpx;
				color: #333;
				text-align: center;
			}
		}
	}
	.calendar-wrap {
		height: 1000rpx;
		.calendar-month {
			.calendar-month-name {
				height: 88rpx;
				line-height: 88rpx;
				text-align: center;
			}
		}
		.day {
			display: flex;
			flex-flow: wrap;
			position: relative;
			.month-index {
				position: absolute;
				top: 50%;
				left: 50%;
				z-index: 0;
				color: rgba(242, 243, 245, 0.8);
				font-size: 320rpx;
				transform: translate(-50%, -50%);
			}
			.day-item {
				height: 128rpx;
				width: calc(100% / 7);
				padding: 10rpx 0;
				position: relative;
				.day-name {
					width: 100%;
					height: 100%;
					display: flex;
					align-items: center;
					justify-content: center;
					font-size: 32rpx;
					color: #333;
					position: relative;
					&.disabled {
						color: #ccc;
					}
					&.active {
						background: #3c9cff;
						border-radius: 8rpx;
						color: #fff;
					}
					&.isEndDate {
						background: #9dd3ff;
						border-radius: 0 8rpx 8rpx 0;
						color: #333 !important;
						&::after {
							position: absolute;
							content: "结束";
							font-size: 20rpx;
							top: 8rpx;
							color: #666;
						}
						&::before {
							color: #666 !important;
						}
					}
					&.isStartDate {
						background: #9dd3ff;
						border-radius: 8rpx 0 0 8rpx;
						color: #333 !important;
						&::after {
							position: absolute;
							content: "开始";
							font-size: 20rpx;
							top: 8rpx;
							color: #666;
						}
						&::before {
							color: #666 !important;
						}
					}
					&.isRangeDate {
						background: rgba(12, 146, 255, 0.12);
					}
					&.isToday {
						color: #3c9cff;
						&::before {
							position: absolute;
							content: "今";
							font-size: 20rpx;
							bottom: 8rpx;
						}
					}
				}
			}
		}
	}
	.range-calendar-wrap {
		height: 630rpx;
	}
	.quick-operate {
		display: flex;
		justify-content: space-between;
		border-top: 2rpx solid #eeeeee;
		padding-top: 24rpx;
		.quick-reset {
			width: 188rpx;
			display: flex;
			flex-flow: column nowrap;
			justify-content: center;
			align-items: center;
			color: #999;
			font-size: 20rpx;
			image {
				width: 44rpx;
				height: 44rpx;
				margin-bottom: 6rpx;
			}
		}
		.quick-confirm {
			flex: 1;
			.submit-button {
				height: 100%;
				display: flex;
				align-items: center;
				justify-content: center;
				background: #49b2fd;
				color: #fff;
				border-radius: 12rpx;
				margin: 0 24rpx;
			}
		}
	}
}
</style>
